home *** CD-ROM | disk | FTP | other *** search
- /**
- ***
- ** Module: SCAN
- ** Neil M. Day
- ** August 9, 1990
- ** Apple Computer, Inc.
- **
- ** An XCMD to collect information on all files on a specified volume.
- **
- ** Calling Form: scan (VolumeName,OutputFileName,[output format])
- ** where VolunmeName is then name of the volume to scan (ex. "Nerd Magnet:")
- ** OutputFileName is the full pathname to the output file
- ** [output format] is the optional output string which may include
- ** F filename
- ** C creator
- ** T type
- ** S size
- ** P the pathname to the file
- **
- ** If the output format is not specified it assumes all fields.
- ** Too few or too many arguments gives you the calling format.
- **
- ** Uses the recursive PBGetCatInfo algorithm described in TN68 to step through
- ** the volume.
- **
- ** This is version 2.0
- **
- ** I would like to extend my most sincere thanks to Jeremy Bornstien, Paul Snively,
- ** James Benninghaus and others in DTS without whom this wouldn't have been possible.
- **
- ** Use the following MPW commands to link this
- **
- ** c -b scan.c
- ** link -w -rt XFCN=22501 ∂
- ** -m ENTRYPOINT∂
- ** -sg scan scan.c.o∂
- ** "{libraries}HyperXLib.o" ∂
- ** "{libraries}Interface.o" ∂
- ** "{Clibraries}"StdCLib.o ∂
- ** "{Clibraries}"CInterface.o ∂
- ** "{Clibraries}"CRuntime.o ∂
- ** -o "Scan Demo Stack"
- **
- ***
- **/
-
- #include <types.h> /* Compiler Interfaces to */
- #include <resources.h> /* various managers and */
- #include <files.h> /* resources ... */
- #include <Packages.h>
- #include <String.h>
- #include <OSEvents.h>
- #include <Memory.h>
- #include <Events.h>
- #include <Errors.h>
- #include <Desk.h>
- #include <Strings.h>
- #include <Memory.h>
- #include <OSUtils.h>
- #include <HyperXCmd.h>
-
- #define BUFFSIZE 522 /* Size of our IO buffer */
- #define NULL 0
-
- #define NEWFILE_CANCELED -1; /* cancel and error codes */
-
- OSErr NewFile (char *FileName,char *buffer,HParmBlkPtr paramBlock); /* Function Prototypes */
- OSErr WriteData (long nBytes,HParmBlkPtr paramBlock);
- OSErr CloseFile (HParmBlkPtr paramBlock);
- void SCopy (unsigned short pos,char *dest,char *source);
- Boolean CheckCancel (void);
- void scan (long searchDir);
- char *pStrcat (unsigned char *s,unsigned char *t);
- char *pStrcpy (unsigned char *s,unsigned char *t);
- char *pathName(long dirID,short vRefNum,char *s);
- char *nameRecover (unsigned long l,unsigned char *s);
- void h2pstr (char *dest,Handle source);
- void h2cstr (char *dest,Handle source);
- Handle str2h (char *str);
- short gimmieVRefNum (const char *name);
-
- CInfoPBRec gBlock; /* Global variables */
- HParamBlockRec it;
- char gName[255];
- char outputStr[30];
- Boolean deadandgone;
-
- typedef Handle A5RefType; /* A5 world management */
- volatile long gHostA5; /* stuff goes here */
-
- extern void A5Init (Ptr myA5);
- extern long A5Size (void);
- OSErr makeA5World (A5RefType *A5Ref);
- long setA5World (A5RefType A5Ref);
- void restoreA5World (long oldA5, A5RefType A5Ref);
- void disposeA5World (A5RefType A5Ref);
-
- pascal void EntryPoint (XCmdPtr paramPtr)
- {
- short target_vRefNum; /* vRefNum for the volume to be scaned*/
- Boolean oktofree = true; /* Only if the newHandle was succesful*/
- char fname[512]; /* container for outPut fileName */
- Handle Error; /* Error message to return.... */
- A5RefType A5Ref; /* container for new A5 global section*/
- char *buffer; /* A buffer for various stuff */
- OSErr res; /* a place for my errors */
-
- res = makeA5World (&A5Ref); /* create new A5 world */
- if (res) { /* if there was a problem... */
- Error = str2h ("SCAN: Ran out of memory (A5 World)"); /* report the problem */
- oktofree = false; /* don'd deallocate a bad handle */
- deadandgone = true; /* set the "Nuked Flag" */
- goto EXITPOINT; /* leave (AAAHHHRRRGGG!!!) */
- }
- gHostA5 = setA5World (A5Ref); /* change to new world; save old one */
-
- deadandgone = false; /* keep it alive, bro */
-
- buffer = NewPtrClear(BUFFSIZE); /* Allocate space for the buffer */
- if (buffer == memFullErr) { /* if an anomoly in allocation occured*/
- Error = str2h ("SCAN: Ran out of memory (buffer)"); /*load appropriate error message */
- deadandgone = true; /* announce a death in the family */
- goto EXITPOINT; /* leave (the pain is INTOLERABLE) */
- }
- switch (paramPtr->paramCount) {
- case 2 :
- h2pstr (buffer,paramPtr->params[0]); /* copy volume name into the buffer */
- h2pstr (fname,paramPtr->params[1]); /* copy output file name into fname */
- SCopy (0,outputStr,"FCTSP\0"); /* default output format */
- break;
- case 3 :
- h2pstr (buffer,paramPtr->params[0]); /* copy volume name into the buffer */
- h2pstr (fname,paramPtr->params[1]); /* copy output file name into fname */
- h2cstr (outputStr,paramPtr->params[2]); /* copy formatting info into its home */
- break;
- default :
- deadandgone = true; /* kill it */
- Error = str2h ("scan (VolumeName,OutputFile[,CMDStr])");
- goto EXITPOINT;
- break;
- }
-
-
- target_vRefNum = gimmieVRefNum (buffer); /* get the vRefNum from name string */
-
- if (target_vRefNum == nsvErr) { /* if there is no such volume... */
- Error = str2h ("SCAN: Couldn't find specified volume"); /* Yet another error message */
- deadandgone = true; /* death */
- goto EXITPOINT; /* leave (I'm meeelllllttttiiinnngg) */
- }
-
- SCopy (0,buffer,"\0"); /* make sure the buffer looks empty */
-
- res = NewFile (fname,buffer,&it); /* Create and open the write file */
- if (res) { /* if NewFile croaked */
- Error = str2h ("SCAN: Couldn't create output file"); /* Moan and complain in an */
- deadandgone = true; /* established stylee... */
- goto EXITPOINT;
- }
-
- gBlock.hfileInfo.ioNamePtr = gName; /* Set up global Paramater Block for */
- gBlock.hfileInfo.ioVRefNum = target_vRefNum; /* various File Manager calls... */
-
- scan (fsRtDirID); /* look at the whole volume */
- if (deadandgone)
- Error = str2h ("SCAN: Canceled"); /* if we died durring the scan... */
-
- res = CloseFile (&it); /* Now that we're all done, close it */
-
- if (res) { /* if we generated an error somewere */
- Error = str2h ("SCAN: ACK!!!"); /* put up an informative error message*/
- deadandgone = true;
- }
-
- EXITPOINT:
-
- if (buffer != memFullErr) DisposPtr (buffer); /* free the buffer (if allocated..) */
-
- if (deadandgone)
- paramPtr->returnValue = Error; /* set up the error return... */
-
- restoreA5World ( gHostA5, A5Ref ); /* nuke my A5 world and restore that */
- if (oktofree) disposeA5World ( A5Ref ); /* That of Hypercard */
- return;
- }
-
- /*
- ** NewFile (char *name,char *buffer,HParmBlkPtr paramBlock)
- ** • Creates a new file called 'name' in the current directory. Returns the
- ** Apropriate set of errors...
- ** • Be forewarned that NewFile is completely destructive to paramBlock.
- ** • After the call to NewFile, paramBlock contains the pointer to the opened and
- ** created file....
- */
- OSErr NewFile (FileName,buffer,paramBlock)
- char *FileName;
- char *buffer;
- HParmBlkPtr paramBlock;
- {
- OSErr result; /* result of file system calls */
-
- paramBlock->fileParam.ioNamePtr = FileName; /* copy filename into Paramater block */
- paramBlock->fileParam.ioVRefNum = NULL; /* Full pathname - unneccisary */
- paramBlock->fileParam.ioDirID = NULL; /* Full pathname - unneccisary.. */
- paramBlock->fileParam.ioCompletion = NULL; /* No completion routine defined */
-
- result = PBHCreate (paramBlock,false); /* create the file */
- if (result != noErr) /* Balk at an error */
- return result;
-
- result = PBHGetFInfo (paramBlock,false); /* Get the existant info on file */
- if (result != noErr) /* Balk at an error */
- return result;
-
- paramBlock->fileParam.ioNamePtr = FileName; /* copy filename into Paramater block */
-
- paramBlock->fileParam.ioCompletion = NULL; /* No completion routine defined */
- paramBlock->fileParam.ioFlFndrInfo.fdType = /* ZAP!! Make it a text file */
- (OSType)'TEXT';
- paramBlock->fileParam.ioFlFndrInfo.fdCreator = /* ZAP!! Make it MY text file */
- (OSType)'CAML';
- paramBlock->fileParam.ioFlVersNum = 0; /* make sure the version is 0 */
- result = PBHSetFInfo (paramBlock,false); /* Update the Information */
- if (result != noErr) /* Balk at an error */
- return result;
-
- paramBlock->ioParam.ioMisc = buffer; /* tell read where me buffer be */
- paramBlock->ioParam.ioBuffer = buffer; /* tell read where me buffer be */
- paramBlock->ioParam.ioPermssn = fsWrPerm; /* Set the file up for writin */
-
- result = PBHOpen (paramBlock,false); /* open the file for writin' */
- if (result != noErr) /* Balk at an error */
- return result;
-
- return noErr; /* Sayoonara , NewFile-san */
- }
-
- /*
- ** WriteData (long nBytes,ParmBlkPtr paramBlock)
- ** •Writes nBytes of the buffer defined in the previous call to NewFile to the file
- ** opened by NewFile.
- ** •Does the appropriate allocations, etc..
- */
- OSErr WriteData (nBytes,paramBlock)
- long nBytes;
- HParmBlkPtr paramBlock;
- {
- OSErr result; /* result of file system calls */
-
- paramBlock->ioParam.ioReqCount = nBytes; /* the number of bytes to allocate */
-
- result = PBWrite ((ParmBlkPtr)paramBlock,false); /* Dump that Chump (to disk) */
- if (result != noErr) return result; /* Balk at an error */
-
- return noErr; /* Our hero rides off into the sunset */
- }
-
- /*
- ** CloseFile (ParmBlkPtr paramBlock)
- ** • Closes the file and flushes the file and volume. Hooray
- */
- OSErr CloseFile (paramBlock)
- HParmBlkPtr paramBlock;
- {
- OSErr result; /* result of file system calls */
-
- result = PBFlushFile ((ParmBlkPtr)paramBlock,false); /* give file TY-DI-BOWL treatment */
- if (result != noErr) {
- Debugger();
- return result; /* Balk at an error */
- }
-
- result = PBClose ((ParmBlkPtr)paramBlock,false); /* Close that puppy */
- if (result != noErr) {
- Debugger();
- return result; /* Balk at an error */
- }
-
- result = PBFlushVol ((ParmBlkPtr)paramBlock,false); /* give Vol. TY-DI-BOWL treatment */
- if (result != noErr) {
- Debugger();
- return result; /* Balk at an error */
- }
-
- return noErr; /* O.K kids, time to go home */
- }
-
- /*
- ** SCopy(pos,dest,source)
- ** Does the 'ol full service string copy thing. Pos specifies the starting position in the
- ** destination. Whopppe.
- */
- void SCopy (pos,dest,source)
- unsigned short pos;
- char dest[],source[];
- {
- unsigned short i=0; /* normal index declaration */
-
- while (dest[i+pos] = source[i]) i++; /* standard string copy routine */
- }
-
- /*
- ** CheckCancel ()
- ** Checks for a command-period event - bealches when one is encountered.
- */
- Boolean CheckCancel (void)
- {
- EventRecord myEvent;
-
- SystemTask (); /* do any pending system operations */
-
- if (deadandgone) return false; /* multiple cancels are not good.... */
-
- if (GetNextEvent(everyEvent^diskMask,&myEvent)) { /* get all events minus disk events */
- if (myEvent.what == keyDown) { /* if it's a keydown, and ... */
- SysBeep(1); /* a little audio feedback... */
- return (myEvent.modifiers & cmdKey) && /* a command - "." ?!?! */
- ((myEvent.message & charCodeMask) == '.'); /* period then return true */
- }
- }
- return false;
- }
-
- /*
- ** scan (directory)
- ** This routine steps through the volume, and writes data on specific files out to
- ** the file previously opened by NewFile.
- ** • Highly recursive
- ** • Highly simple
- ** • Highly gleaned from DTS sample code
- */
- void scan (searchDir)
- long searchDir;
- {
- char string[1024]; /* BIG string for pathnames */
- char type [6]; /* little string for type/creator info*/
- char numObytes[256]; /* a place for my byte string */
- long totalsize; /* total Size of the file */
- Boolean dirFlag = false; /*"This is a directory" flag... */
- Boolean first = true; /* first time through flag... */
- short index = 1; /* index into the current directory */
- short cntr; /* your generic counter... */
- OSErr err; /* container for errors */
-
- if (deadandgone) return; /* sprial up through the recursion */
-
- do {
- gBlock.hfileInfo.ioFDirIndex = index; /* set file up file index */
- gBlock.hfileInfo.ioDirID = searchDir; /* set the directory to search */
-
- if (CheckCancel ()) { /* exit routine on a CANCEL request */
- deadandgone = true; /* unleash the recursion killer.... */
- return;
- }
-
- err = PBGetCatInfo (&gBlock,false); /* get current file info */
-
- if (!err) {
- if (first) { /* only need to get the pathname once */
- strcpy (&string[0], p2cstr(pathName(dirFlag ? gBlock.hfileInfo.ioDirID :
- gBlock.hfileInfo.ioFlParID,
- gBlock.hfileInfo.ioVRefNum, /* Structures make such */
- &string[0]))); /* nice readable code.... */
- first = false;
- }
-
- if ((gBlock.hfileInfo.ioFlAttrib>>4) & 0x01) /* if the current file is a directory */
- dirFlag = true; /* set the directory flag to true */
- else
- dirFlag = false; /* set the directory flag to false */
-
- if (!dirFlag) { /* if it's not a directory */
- totalsize = gBlock.hfileInfo.ioFlPyLen + gBlock.hfileInfo.ioFlRPyLen;
- NumToString(totalsize,numObytes); /* stuff the bytecount to a str*/
- for (cntr = 0; cntr < strlen (outputStr); cntr++) {
- switch (outputStr[cntr]) {
- case 'F':
- SCopy (0,it.ioParam.ioBuffer,"\"\0");
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer,
- p2cstr(gBlock.hfileInfo.ioNamePtr));
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer, "\" \0");
- break;
- case 'C' :
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer,
- nameRecover (gBlock.hfileInfo.ioFlFndrInfo.fdCreator,&type[0]));
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer, " \0");
- break;
- case 'T' :
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer,
- nameRecover (gBlock.hfileInfo.ioFlFndrInfo.fdType,&type[0]));
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer, " \0");
- break;
- case 'S' :
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer,
- p2cstr(numObytes));
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer, " \0");
- break;
- case 'P' :
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer, "\"\0");
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer,
- string);
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer, "\"\0");
- break;
- default :
- break;
- }
- }
- SCopy (strlen (it.ioParam.ioBuffer),it.ioParam.ioBuffer, "\n\0");
- err = WriteData (strlen (it.ioParam.ioBuffer),&it); /* write the info to disk */
- }
-
- if (dirFlag) scan(gBlock.hfileInfo.ioDirID); /* recurse with new directory ID */
- ++index; /* incriment the index */
- }
- } while (!err); /* while there is not an error */
- } /* end of scan */
-
- /*
- ** pathName (dirID,vRefNum,s)
- ** returns a string containing the full pathname to the current file or directory
- ** this code is snached from the DTS sample code StdFile.c (but slightly modified).
- ** Added support for both files and directories. NOT A/UX compatable...
- */
- char *pathName(dirID,vRefNum,s)
- long dirID;
- short vRefNum;
- char *s;
- {
- OSErr err; /* error container */
- CInfoPBRec block; /* infoBlock to be used CatInfo calls */
- Str255 directoryName; /* a place to stuff my directory name */
-
- *s = 0;
- block.dirInfo.ioNamePtr = &directoryName;
-
- block.dirInfo.ioDrParID = dirID;
-
- do {
- block.dirInfo.ioFDirIndex = -1; /* Specify vRefNum and DirID for call */
- block.dirInfo.ioVRefNum = vRefNum; /* set the ParamBlock's vRefNum */
- block.dirInfo.ioDrDirID = block.dirInfo.ioDrParID; /* set the ParamBlock's DirID */
-
- err = PBGetCatInfo (&block,false); /* get information on catalogue */
- if (err) break; /* get me outta here...... */
-
- pStrcat (&directoryName,"\p:"); /* add a colon to the begining... */
- pStrcat (&directoryName,s); /* prepose newly found directory name */
- pStrcpy (s,&directoryName); /* swap the two */
-
- } while (block.dirInfo.ioDrDirID != fsRtDirID); /* loop till we hit the ceiling (fig) */
-
- return (s); /* cough up the result */
- }
-
- /*
- ** pStrcat,pStrcpy
- ** two plagarized routines for dealing with pascal strings. Yea. Hooray. Whoopie
- ** DISCLAIMER - I didn't write this stuff, therefore I take no responsibility for the
- * ease of comprehension of this code. If you don't understand C well, tough titties.
- */
- char *pStrcat (s,t)
- unsigned char *s, *t;
- {
- unsigned char *s2;
- short tLen;
-
- s2 = s + *s;
- *s += (tLen = *t);
- for (++tLen; --tLen; s2[tLen] = t[tLen]);
- return (s);
- }
-
- char *pStrcpy (s,t)
- unsigned char *s, *t;
- {
- short tLen;
-
- for (tLen = *t + 1; tLen--; s[tLen] = t[tLen]);
- return (s);
- }
-
- /*
- ** nameRecoer (it,s)
- ** returns a ascii string from a long integer (handy when dealing with creator types)
- */
- char *nameRecover (l,s)
- unsigned long l;
- unsigned char *s;
- {
- short cnt;
-
- for (cnt = 0; cnt < 4; cnt++)
- s[cnt] = (l >> (8*(3-cnt))) & 0xff; /* break out bytes & stuff 'em */
- /* nice clean little alg, huh... */
- s[4] = '\0';
-
- return (s);
- }
-
- /*
- ** A5World stuff
- ** Ugly Ugly Ugly.
- ** Undocumented Undocumented Undocumented.
- ** Plagerized Plagerized Plagerized.
- */
- OSErr makeA5World ( A5RefType *A5Ref )
- {
- *A5Ref = NewHandle ( A5Size ( ) );
- if ((*A5Ref == 0) || (MemError() != noErr)) /* if the allocation crapped out */
- return memFullErr; /* return the time honored error */
- HLock ( *A5Ref );
- A5Init ( ( Ptr ) ( * ( *A5Ref ) + A5Size ( ) - 32 ) );
- HUnlock ( *A5Ref );
- }
-
- long setA5World ( A5RefType A5Ref )
- {
- HLock ( A5Ref );
- return ( SetA5 ( ( long ) ( *A5Ref ) + A5Size ( ) - 32 ) );
- }
-
- void restoreA5World ( long oldA5, A5RefType A5Ref )
- {
- if ( SetA5 ( oldA5 ) )
- HUnlock ( A5Ref );
- }
-
- void disposeA5World ( A5RefType A5Ref )
- {
- DisposHandle ( A5Ref );
- }
-
- /*
- ** h2pstr (dest,source)
- ** does what it says
- **
- */
- void h2pstr (dest,source)
- char *dest;
- Handle source;
- {
- strcpy ((char *) dest, *source);
- dest = c2pstr (dest);
- }
-
- /*
- ** h2cstr (dest,source)
- ** also does what it says
- **
- */
- void h2cstr (dest,source)
- char *dest;
- Handle source;
- {
- strcpy ((char *) dest, *source);
- }
-
- /*
- ** str2h (str)
- ** copies a string into a handle and returns it
- */
-
- Handle str2h (str)
- char *str;
- {
- Handle new;
-
- new = NewHandleClear ((long) strlen(str) + 1);
- strcpy ((char *) (*new), str);
-
- return (new);
- }
-
- /*
- ** gimmieVRefNum (name)
- ** returns a vRefNum from a volume name
- */
- short gimmieVRefNum (name)
- const char *name;
- {
- HParamBlockRec sBlock;
- WDPBRec Info;
- OSErr res;
-
- sBlock.fileParam.ioNamePtr = name; /* give the pointer some memory */
- sBlock.fileParam.ioVRefNum = -20; /* Way out of range to generate errror*/
- sBlock.volumeParam.ioVolIndex = -1; /* set up fileName and VrefNum call */
- sBlock.fileParam.ioCompletion = NULL; /* Vestigial procedure nullification..*/
-
- res = PBHGetVInfo (&sBlock,false); /* get volume info */
- if (res) /* if the info call choked, return err*/
- return nsvErr;
-
- Info.ioVRefNum = sBlock.fileParam.ioVRefNum; /* get the new vol's vrefnum */
- Info.ioWDIndex = 0; /* get dir info from vRefNum only */
- Info.ioWDProcID = 0; /* Include info about WDs of all procs*/
-
- res = PBGetWDInfo ( ((WDPBPtr)&Info) ,false); /* seperate volume and directory info */
- if (res) /* if the info call choked, return err*/
- return nsvErr;
-
- return (Info.ioWDVRefNum); /* If we survived, return the vRefNum */
- }
-